package com.steve.summary.three_PC;

import java.util.concurrent.atomic.AtomicReference;

/**
 * @Author: STEVE
 * @Description: 参与者
 * @since: 2025-05-21
 */
public class Participant {

    private final String participantId;

    // 参与者状态：INIT, CAN_COMMIT, PRE_COMMIT, COMMITTED, ABORTED
    private final AtomicReference<State> state = new AtomicReference<>(State.INIT);

    // 事务日志（模拟持久化存储）
    private final TransactionLog transactionLog = new TransactionLog();

    // 用于模拟故障的测试标志
    private boolean forceFail = false;

    public Participant(String participantId) {
        this.participantId = participantId;
    }

    public void setForceFail(boolean flag) {
        this.forceFail = flag;
    }

    public enum State {INIT, CAN_COMMIT, PRE_COMMIT, COMMITTED, ABORTED}

    /**
     * Phase 1: 检查是否可以提交（不锁定资源）
     */
    public synchronized boolean canCommit(String txId) {
        if (state.get() != State.INIT) {
            return false; // 已参与其他事务
        }
        boolean resourceAvailable = checkResourceAvailable(txId); // 模拟资源检查
        if (resourceAvailable) {
            state.set(State.CAN_COMMIT);
            transactionLog.log(participantId, txId, "CAN_COMMIT");
            return true;
        }
        return false;
    }

    /**
     * Phase 2: 预提交（锁定资源，写日志）
     */
    public synchronized boolean preCommit(String txId) {
        if (forceFail) {
            System.out.println("[Participant-" + participantId + "] 模拟PRE_COMMIT失败");
            return false;
        }
        if (state.get() != State.CAN_COMMIT) {
            return false;
        }
        lockResources(txId); // 模拟锁定资源
        state.set(State.PRE_COMMIT);
        transactionLog.log(participantId, txId, "PRE_COMMIT");
        return true;
    }

    /**
     * Phase 3: 最终提交
     */
    public synchronized boolean doCommit(String txId) {
        if (state.get() != State.PRE_COMMIT) {
            return false;
        }
        commitTransaction(txId); // 模拟提交
        state.set(State.COMMITTED);
        transactionLog.log(participantId, txId, "COMMITTED");
        return true;
    }

    /**
     * 超时后的自主决策（根据3PC协议）
     */
    public synchronized void handleTimeout(String txId) {
        if (state.get() == State.PRE_COMMIT) {
            // 超时后若处于PRE_COMMIT，则自主提交
            doCommit(txId);
        } else if (state.get() == State.CAN_COMMIT) {
            // 超时后若处于CAN_COMMIT，则终止事务
            state.set(State.ABORTED);
            transactionLog.log(participantId, txId, "ABORTED (TIMEOUT)");
        }
    }

    // ---- 模拟方法（实际需替换为真实操作）----
    private boolean checkResourceAvailable(String txId) {
        return true; // 假设资源总是可用
    }

    private void lockResources(String txId) {
        System.out.println("[Participant-" + participantId + "] 锁定资源, TX: " + txId);
    }

    private void commitTransaction(String txId) {
        System.out.println("[Participant-" + participantId + "] 提交事务, TX: " + txId);
    }

    // 获取参与者ID（供协调者调用）
    public String getParticipantId() {
        return participantId;
    }

    // 用于在事务失败时让参与者回滚操作
    public synchronized boolean abort(String txId) {
        if (state.get() == State.INIT || state.get() == State.CAN_COMMIT) {
            // 如果还未预提交，直接终止事务
            state.set(State.ABORTED);
            System.out.println("[Participant-" + participantId + "] ABORTED: " + txId);
            return true;
        } else if (state.get() == State.PRE_COMMIT) {
            // 如果已预提交，需要回滚（执行补偿操作）
            rollback(txId);
            state.set(State.ABORTED);
            System.out.println("[Participant-" + participantId + "] ROLLBACK: " + txId);
            return true;
        }
        return false;   // 其他状态无法终止
    }

    private void rollback(String txId) {
        // 实际项目这里需要：
        // 1. 根据undo日志回滚数据
        // 2. 释放锁资源
        System.out.println("[Participant-" + participantId + "] 执行回滚操作, TX: " + txId);
    }

}
